package cmd

import (
	"context"
	"fmt"
	"net/http"
	"os"
	"os/signal"
	"syscall"
	"time"

	"BookStack/internal/application/article"
	"BookStack/internal/application/book"
	"BookStack/internal/application/category"
	"BookStack/internal/application/navigation"
	"BookStack/internal/application/page"
	"BookStack/internal/application/tag"
	"BookStack/internal/application/user"
	"BookStack/internal/domain"
	domainEvents "BookStack/internal/domain/events"
	"BookStack/internal/infrastructure/core"
	infraEvents "BookStack/internal/infrastructure/events"
	"BookStack/internal/infrastructure/persistence"
	"BookStack/internal/interfaces/api"
	"BookStack/internal/interfaces/middleware"

	"github.com/gin-gonic/gin"
	"github.com/sirupsen/logrus"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
)

// Serve 运行API服务
func Serve() error {
	// 加载配置
	config := core.GetConfig()

	// 初始化日志
	logger := setupLogger(config)
	logger.Info("正在启动 BookStack API 服务...")

	// 初始化数据库连接
	db, err := setupDatabase(config)
	if err != nil {
		return fmt.Errorf("连接数据库失败: %v", err)
	}

	// 初始化存储库
	repositories := setupRepositories(db)

	// 初始化事件发布器
	eventPublisher := setupEventPublisher(logger)

	// 初始化应用服务
	userService, articleService, bookService, pageService, categoryService, tagService, navigationService := setupServices(repositories, eventPublisher)

	// 设置 Gin
	router := setupRouter(config)

	// 创建处理器
	handlers := setupHandlers(userService, articleService, bookService, pageService, categoryService, tagService, navigationService)

	// 注册路由
	api.RegisterRoutes(router, handlers)

	// 启动服务器
	srv := &http.Server{
		Addr:         ":" + config.Server.Port,
		Handler:      router,
		ReadTimeout:  config.Server.ReadTimeout,
		WriteTimeout: config.Server.WriteTimeout,
	}

	// 启动 HTTP 服务
	go func() {
		logger.Infof("服务器启动在 %s 端口", config.Server.Port)
		if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
			logger.Fatalf("启动服务器失败: %v", err)
		}
	}()

	// 优雅关闭
	return gracefulShutdown(srv, config.Server.ShutdownTimeout, logger)
}

// setupLogger 设置日志
func setupLogger(config *core.Config) *logrus.Logger {
	logger := logrus.New()

	// 设置日志级别
	level, err := logrus.ParseLevel(config.Log.Level)
	if err != nil {
		level = logrus.InfoLevel
	}
	logger.SetLevel(level)

	// 设置日志格式
	if config.App.Env == "production" {
		logger.SetFormatter(&logrus.JSONFormatter{})
	} else {
		logger.SetFormatter(&logrus.TextFormatter{
			FullTimestamp: true,
		})
	}

	return logger
}

// setupDatabase 连接数据库
func setupDatabase(config *core.Config) (*gorm.DB, error) {
	dsn := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=%s&parseTime=True&loc=Local",
		config.DB.Username,
		config.DB.Password,
		config.DB.Host,
		config.DB.Port,
		config.DB.Name,
		config.DB.Charset,
	)

	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
	if err != nil {
		return nil, err
	}

	// 设置连接池
	sqlDB, err := db.DB()
	if err != nil {
		return nil, err
	}

	sqlDB.SetMaxIdleConns(config.DB.MaxIdle)
	sqlDB.SetMaxOpenConns(config.DB.MaxOpen)
	sqlDB.SetConnMaxLifetime(time.Hour)

	return db, nil
}

// setupRepositories 初始化存储库
func setupRepositories(db *gorm.DB) *persistence.RepositoryFactory {
	return persistence.NewRepositoryFactory(db)
}

// setupEventPublisher 初始化事件发布器
func setupEventPublisher(logger *logrus.Logger) domainEvents.Publisher {
	// 使用基础设施层提供的NewPublisher方法
	publisher := infraEvents.NewPublisher()

	// 创建领域事件适配器
	return &domainEventsAdapter{publisher: publisher}
}

// setupServices 初始化应用服务
func setupServices(repositories *persistence.RepositoryFactory, eventPublisher domainEvents.Publisher) (
	userService user.Service,
	articleService article.Service,
	bookService book.ApplicationService,
	pageService page.Service,
	categoryService category.Service,
	tagService tag.Service,
	navigationService navigation.Service,
	// TODO: 添加其他服务
) {
	// 初始化领域服务
	domainServices := domain.NewService(
		repositories.UserRepository,
		repositories.ArticleRepository,
		repositories.BookRepository,
		repositories.ChapterRepository,
		repositories.RecycleBinRepository,
		repositories.PageRepository,
		repositories.CategoryRepository,
		repositories.TagRepository,
		repositories.NavigationRepository,
		// TODO: 添加其他服务
	)

	// 初始化应用服务
	userService = user.NewService(domainServices.User, eventPublisher)
	articleService = article.NewService(domainServices.Article, eventPublisher)
	bookService = book.NewService(domainServices.Book, eventPublisher)
	pageService = page.NewService(domainServices.Page, eventPublisher)
	categoryService = category.NewService(domainServices.Category, eventPublisher)
	tagService = tag.NewService(domainServices.Tag, eventPublisher)
	navigationService = navigation.NewService(domainServices.Navigation, eventPublisher)
	// TODO: 添加其他服务

	return
}

// domainEventsAdapter 领域事件适配器，将基础设施层的事件发布器适配为领域层的事件发布器
type domainEventsAdapter struct {
	publisher infraEvents.Publisher
}

// Publish 实现领域事件发布者接口
func (a *domainEventsAdapter) Publish(ctx context.Context, event domainEvents.Event) error {
	// 创建基础设施层事件
	infraEvent := &infraEvents.BaseEvent{
		ID:        event.EventID(),
		Type:      event.EventType(),
		Payload:   event.EventData(),
		Timestamp: event.EventTime(),
	}

	return a.publisher.Publish(ctx, infraEvent)
}

// AsyncPublish 实现领域事件异步发布
func (a *domainEventsAdapter) AsyncPublish(ctx context.Context, event domainEvents.Event) {
	// 创建基础设施层事件
	infraEvent := &infraEvents.BaseEvent{
		ID:        event.EventID(),
		Type:      event.EventType(),
		Payload:   event.EventData(),
		Timestamp: event.EventTime(),
	}

	// 异步发布事件，忽略错误返回
	go func() {
		err := a.publisher.AsyncPublish(ctx, infraEvent)
		if err != nil {
			// 可以在这里记录日志，但不传递错误
			fmt.Printf("发布事件失败: %v\n", err)
		}
	}()
}

// Subscribe 实现领域事件订阅
func (a *domainEventsAdapter) Subscribe(eventType string, handler domainEvents.EventHandler) {
	// 因为基础设施层和领域层接口不兼容，这里只保留方法签名，实际不进行订阅
	// 在实际应用中需要创建适配器处理函数
}

// Unsubscribe 实现取消订阅
func (a *domainEventsAdapter) Unsubscribe(eventType string, handler domainEvents.EventHandler) {
	// 同上，因接口不兼容，只保留方法签名
}

// eventHandlerAdapter 事件处理器适配器
type eventHandlerAdapter struct {
	handler domainEvents.EventHandler
}

// Handle 处理事件 - 这个方法未被使用
func (a *eventHandlerAdapter) Handle(ctx context.Context, event infraEvents.Event) error {
	// 创建领域事件
	domainEvent := &domainEventAdapter{event}

	// 处理事件
	return a.handler.Handle(ctx, domainEvent)
}

// domainEventAdapter 领域事件适配器
type domainEventAdapter struct {
	event infraEvents.Event
}

// EventType 实现Event接口
func (a *domainEventAdapter) EventType() string {
	return a.event.GetType()
}

// EventData 实现Event接口
func (a *domainEventAdapter) EventData() interface{} {
	return a.event.GetPayload()
}

// EventID 实现Event接口
func (a *domainEventAdapter) EventID() string {
	return a.event.GetID()
}

// EventTime 实现Event接口
func (a *domainEventAdapter) EventTime() time.Time {
	return a.event.GetTimestamp()
}

// setupHandlers 设置处理器
func setupHandlers(
	userService user.Service,
	articleService article.Service,
	bookService book.ApplicationService,
	pageService page.Service,
	categoryService category.Service,
	tagService tag.Service,
	navigationService navigation.Service,
	// TODO: 添加其他服务
) *api.Handlers {
	return api.NewHandlers(
		userService,
		articleService,
		bookService,
		pageService,
		categoryService,
		tagService,
		navigationService,
		// TODO: 添加其他服务
	)
}

// setupRouter 设置路由
func setupRouter(config *core.Config) *gin.Engine {
	// 设置运行模式
	if config.App.Env == "production" {
		gin.SetMode(gin.ReleaseMode)
	}

	router := gin.New()

	// 中间件
	router.Use(gin.Recovery())
	router.Use(middleware.RequestLogger())

	// CORS 设置
	router.Use(func(c *gin.Context) {
		c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
		c.Writer.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, DELETE, OPTIONS")
		c.Writer.Header().Set("Access-Control-Allow-Headers", "Origin, Content-Type, Accept, Authorization")
		c.Writer.Header().Set("Access-Control-Expose-Headers", "Content-Length")
		c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")

		if c.Request.Method == "OPTIONS" {
			c.AbortWithStatus(http.StatusNoContent)
			return
		}

		c.Next()
	})

	return router
}

// gracefulShutdown 优雅关闭
func gracefulShutdown(srv *http.Server, timeout time.Duration, logger *logrus.Logger) error {
	// 等待中断信号以优雅地关闭服务器
	quit := make(chan os.Signal, 1)
	signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
	<-quit
	logger.Info("正在关闭服务器...")

	// 创建一个带超时的上下文来通知服务器关闭
	ctx, cancel := context.WithTimeout(context.Background(), timeout)
	defer cancel()

	if err := srv.Shutdown(ctx); err != nil {
		return fmt.Errorf("服务器强制关闭: %v", err)
	}

	logger.Info("服务器已优雅关闭")
	return nil
}
